home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Games / Doom / ADoom-0.8 / ADoom_src / p_map.c < prev    next >
C/C++ Source or Header  |  1998-06-24  |  29KB  |  1,351 lines

  1. // Emacs style mode select   -*- C++ -*- 
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id:$
  5. //
  6. // Copyright (C) 1993-1996 by id Software, Inc.
  7. //
  8. // This source is available for distribution and/or modification
  9. // only under the terms of the DOOM Source Code License as
  10. // published by id Software. All rights reserved.
  11. //
  12. // The source is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
  15. // for more details.
  16. //
  17. // $Log:$
  18. //
  19. // DESCRIPTION:
  20. //    Movement, collision handling.
  21. //    Shooting and aiming.
  22. //
  23. //-----------------------------------------------------------------------------
  24.  
  25. static const char
  26. rcsid[] = "$Id: p_map.c,v 1.5 1997/02/03 22:45:11 b1 Exp $";
  27.  
  28. #include <stdlib.h>
  29.  
  30. #include "m_bbox.h"
  31. #include "m_random.h"
  32. #include "i_system.h"
  33.  
  34. #include "doomdef.h"
  35. #include "p_local.h"
  36.  
  37. #include "s_sound.h"
  38.  
  39. // State.
  40. #include "doomstat.h"
  41. #include "r_state.h"
  42. // Data.
  43. #include "sounds.h"
  44.  
  45.  
  46. fixed_t        tmbbox[4];
  47. mobj_t*        tmthing;
  48. int        tmflags;
  49. fixed_t        tmx;
  50. fixed_t        tmy;
  51.  
  52.  
  53. // If "floatok" true, move would be ok
  54. // if within "tmfloorz - tmceilingz".
  55. boolean        floatok;
  56.  
  57. fixed_t        tmfloorz;
  58. fixed_t        tmceilingz;
  59. fixed_t        tmdropoffz;
  60.  
  61. // keep track of the line that lowers the ceiling,
  62. // so missiles don't explode against sky hack walls
  63. line_t*        ceilingline;
  64.  
  65. // keep track of special lines as they are hit,
  66. // but don't process them until the move is proven valid
  67. #define MAXSPECIALCROSS        20   /* was 8 */
  68.  
  69. line_t*        spechit[MAXSPECIALCROSS];
  70. int        numspechit = 0;
  71.  
  72.  
  73.  
  74. void check_numspechit (char *msg)
  75. {
  76.   if (numspechit < 0 || numspechit >= MAXSPECIALCROSS) {
  77.     fprintf (stderr, "Numspechit = %d > %d at %s\n", numspechit,
  78.              MAXSPECIALCROSS, msg);
  79.     exit (20);
  80.   }
  81. }
  82.  
  83. //
  84. // TELEPORT MOVE
  85. // 
  86.  
  87. //
  88. // PIT_StompThing
  89. //
  90. boolean PIT_StompThing (mobj_t* thing)
  91. {
  92.     fixed_t    blockdist;
  93.         
  94.     if (!(thing->flags & MF_SHOOTABLE) )
  95.     return true;
  96.         
  97.     blockdist = thing->radius + tmthing->radius;
  98.     
  99.     if ( iabs(thing->x - tmx) >= blockdist
  100.      || iabs(thing->y - tmy) >= blockdist )
  101.     {
  102.     // didn't hit it
  103.     return true;
  104.     }
  105.     
  106.     // don't clip against self
  107.     if (thing == tmthing)
  108.     return true;
  109.     
  110.     // monsters don't stomp things except on boss level
  111.     if ( !tmthing->player && gamemap != 30)
  112.     return false;    
  113.         
  114.     P_DamageMobj (thing, tmthing, tmthing, 10000);
  115.     
  116.     return true;
  117. }
  118.  
  119.  
  120. //
  121. // P_TeleportMove
  122. //
  123. boolean
  124. P_TeleportMove
  125. ( mobj_t*    thing,
  126.   fixed_t    x,
  127.   fixed_t    y )
  128. {
  129.     int            xl;
  130.     int            xh;
  131.     int            yl;
  132.     int            yh;
  133.     int            bx;
  134.     int            by;
  135.     
  136.     subsector_t*    newsubsec;
  137.     
  138.     // kill anything occupying the position
  139.     tmthing = thing;
  140.     tmflags = thing->flags;
  141.     
  142.     tmx = x;
  143.     tmy = y;
  144.     
  145.     tmbbox[BOXTOP] = y + tmthing->radius;
  146.     tmbbox[BOXBOTTOM] = y - tmthing->radius;
  147.     tmbbox[BOXRIGHT] = x + tmthing->radius;
  148.     tmbbox[BOXLEFT] = x - tmthing->radius;
  149.  
  150.     newsubsec = R_PointInSubsector (x,y);
  151.     ceilingline = NULL;
  152.     
  153.     // The base floor/ceiling is from the subsector
  154.     // that contains the point.
  155.     // Any contacted lines the step closer together
  156.     // will adjust them.
  157.     tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  158.     tmceilingz = newsubsec->sector->ceilingheight;
  159.             
  160.     validcount++;
  161.     numspechit = 0;
  162.     
  163.     // stomp on any things contacted
  164.     xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  165.     xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  166.     yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  167.     yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  168.  
  169.     for (bx=xl ; bx<=xh ; bx++)
  170.     for (by=yl ; by<=yh ; by++)
  171.         if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
  172.         return false;
  173.     
  174.     // the move is ok,
  175.     // so link the thing into its new position
  176.     P_UnsetThingPosition (thing);
  177.  
  178.     thing->floorz = tmfloorz;
  179.     thing->ceilingz = tmceilingz;    
  180.     thing->x = x;
  181.     thing->y = y;
  182.  
  183.     P_SetThingPosition (thing);
  184.     
  185.     return true;
  186. }
  187.  
  188.  
  189. //
  190. // MOVEMENT ITERATOR FUNCTIONS
  191. //
  192.  
  193.  
  194. //
  195. // PIT_CheckLine
  196. // Adjusts tmfloorz and tmceilingz as lines are contacted
  197. //
  198. boolean PIT_CheckLine (line_t* ld)
  199. {
  200.     if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
  201.     || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
  202.     || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
  203.     || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] )
  204.     return true;
  205.  
  206.     if (P_BoxOnLineSide (tmbbox, ld) != -1)
  207.     return true;
  208.         
  209.     // A line has been hit
  210.     
  211.     // The moving thing's destination position will cross
  212.     // the given line.
  213.     // If this should not be allowed, return false.
  214.     // If the line is special, keep track of it
  215.     // to process later if the move is proven ok.
  216.     // NOTE: specials are NOT sorted by order,
  217.     // so two special lines that are only 8 pixels apart
  218.     // could be crossed in either order.
  219.     
  220.     if (!ld->backsector)
  221.     return false;        // one sided line
  222.         
  223.     if (!(tmthing->flags & MF_MISSILE) )
  224.     {
  225.     if ( ld->flags & ML_BLOCKING )
  226.         return false;    // explicitly blocking everything
  227.  
  228.     if ( !tmthing->player && ld->flags & ML_BLOCKMONSTERS )
  229.         return false;    // block monsters only
  230.     }
  231.  
  232.     // set openrange, opentop, openbottom
  233.     P_LineOpening (ld);    
  234.     
  235.     // adjust floor / ceiling heights
  236.     if (opentop < tmceilingz)
  237.     {
  238.     tmceilingz = opentop;
  239.     ceilingline = ld;
  240.     }
  241.  
  242.     if (openbottom > tmfloorz)
  243.     tmfloorz = openbottom;    
  244.  
  245.     if (lowfloor < tmdropoffz)
  246.     tmdropoffz = lowfloor;
  247.         
  248.     // if contacted a special line, add it to the list
  249.     if (ld->special /* && numspechit < MAXSPECIALCROSS */ )
  250.     {
  251.         check_numspechit ("PIT_CheckLine");
  252.     spechit[numspechit] = ld;
  253.     numspechit++;
  254.     }
  255.  
  256.     return true;
  257. }
  258.  
  259. //
  260. // PIT_CheckThing
  261. //
  262. boolean PIT_CheckThing (mobj_t* thing)
  263. {
  264.     fixed_t        blockdist;
  265.     boolean        solid;
  266.     int            damage;
  267.         
  268.     if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE) ))
  269.     return true;
  270.     
  271.     blockdist = thing->radius + tmthing->radius;
  272.  
  273.     if ( iabs(thing->x - tmx) >= blockdist
  274.      || iabs(thing->y - tmy) >= blockdist )
  275.     {
  276.     // didn't hit it
  277.     return true;    
  278.     }
  279.     
  280.     // don't clip against self
  281.     if (thing == tmthing)
  282.     return true;
  283.     
  284.     // check for skulls slamming into things
  285.     if (tmthing->flags & MF_SKULLFLY)
  286.     {
  287.     damage = ((P_Random()%8)+1)*tmthing->info->damage;
  288.     
  289.     P_DamageMobj (thing, tmthing, tmthing, damage);
  290.     
  291.     tmthing->flags &= ~MF_SKULLFLY;
  292.     tmthing->momx = tmthing->momy = tmthing->momz = 0;
  293.     
  294.     P_SetMobjState (tmthing, tmthing->info->spawnstate);
  295.     
  296.     return false;        // stop moving
  297.     }
  298.  
  299.     
  300.     // missiles can hit other things
  301.     if (tmthing->flags & MF_MISSILE)
  302.     {
  303.     // see if it went over / under
  304.     if (tmthing->z > thing->z + thing->height)
  305.         return true;        // overhead
  306.     if (tmthing->z+tmthing->height < thing->z)
  307.         return true;        // underneath
  308.         
  309.     if (tmthing->target && (
  310.         tmthing->target->type == thing->type || 
  311.         (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)||
  312.         (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) ) )
  313.     {
  314.         // Don't hit same species as originator.
  315.         if (thing == tmthing->target)
  316.         return true;
  317.  
  318.         if (thing->type != MT_PLAYER)
  319.         {
  320.         // Explode, but do no damage.
  321.         // Let players missile other players.
  322.         return false;
  323.         }
  324.     }
  325.     
  326.     if (! (thing->flags & MF_SHOOTABLE) )
  327.     {
  328.         // didn't do any damage
  329.         return !(thing->flags & MF_SOLID);    
  330.     }
  331.     
  332.     // damage / explode
  333.     damage = ((P_Random()%8)+1)*tmthing->info->damage;
  334.     P_DamageMobj (thing, tmthing, tmthing->target, damage);
  335.  
  336.     // don't traverse any more
  337.     return false;                
  338.     }
  339.     
  340.     // check for special pickup
  341.     if (thing->flags & MF_SPECIAL)
  342.     {
  343.     solid = thing->flags&MF_SOLID;
  344.     if (tmflags&MF_PICKUP)
  345.     {
  346.         // can remove thing
  347.         P_TouchSpecialThing (thing, tmthing);
  348.     }
  349.     return !solid;
  350.     }
  351.     
  352.     return !(thing->flags & MF_SOLID);
  353. }
  354.  
  355.  
  356. //
  357. // MOVEMENT CLIPPING
  358. //
  359.  
  360. //
  361. // P_CheckPosition
  362. // This is purely informative, nothing is modified
  363. // (except things picked up).
  364. // 
  365. // in:
  366. //  a mobj_t (can be valid or invalid)
  367. //  a position to be checked
  368. //   (doesn't need to be related to the mobj_t->x,y)
  369. //
  370. // during:
  371. //  special things are touched if MF_PICKUP
  372. //  early out on solid lines?
  373. //
  374. // out:
  375. //  newsubsec
  376. //  floorz
  377. //  ceilingz
  378. //  tmdropoffz
  379. //   the lowest point contacted
  380. //   (monsters won't move to a dropoff)
  381. //  speciallines[]
  382. //  numspeciallines
  383. //
  384. boolean
  385. P_CheckPosition
  386. ( mobj_t*    thing,
  387.   fixed_t    x,
  388.   fixed_t    y )
  389. {
  390.     int            xl;
  391.     int            xh;
  392.     int            yl;
  393.     int            yh;
  394.     int            bx;
  395.     int            by;
  396.     subsector_t*    newsubsec;
  397.  
  398.     tmthing = thing;
  399.     tmflags = thing->flags;
  400.     
  401.     tmx = x;
  402.     tmy = y;
  403.     
  404.     tmbbox[BOXTOP] = y + tmthing->radius;
  405.     tmbbox[BOXBOTTOM] = y - tmthing->radius;
  406.     tmbbox[BOXRIGHT] = x + tmthing->radius;
  407.     tmbbox[BOXLEFT] = x - tmthing->radius;
  408.  
  409.     newsubsec = R_PointInSubsector (x,y);
  410.     ceilingline = NULL;
  411.     
  412.     // The base floor / ceiling is from the subsector
  413.     // that contains the point.
  414.     // Any contacted lines the step closer together
  415.     // will adjust them.
  416.     tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
  417.     tmceilingz = newsubsec->sector->ceilingheight;
  418.             
  419.     validcount++;
  420.     numspechit = 0;
  421.  
  422.     if ( tmflags & MF_NOCLIP )
  423.     return true;
  424.     
  425.     // Check things first, possibly picking things up.
  426.     // The bounding box is extended by MAXRADIUS
  427.     // because mobj_ts are grouped into mapblocks
  428.     // based on their origin point, and can overlap
  429.     // into adjacent blocks by up to MAXRADIUS units.
  430.     xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
  431.     xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
  432.     yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
  433.     yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
  434.  
  435.     for (bx=xl ; bx<=xh ; bx++)
  436.     for (by=yl ; by<=yh ; by++)
  437.         if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
  438.         return false;
  439.     
  440.     // check lines
  441.     xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
  442.     xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
  443.     yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
  444.     yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
  445.  
  446.     for (bx=xl ; bx<=xh ; bx++)
  447.     for (by=yl ; by<=yh ; by++)
  448.         if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
  449.         return false;
  450.  
  451.     return true;
  452. }
  453.  
  454.  
  455. //
  456. // P_TryMove
  457. // Attempt to move to a new position,
  458. // crossing special lines unless MF_TELEPORT is set.
  459. //
  460. boolean
  461. P_TryMove
  462. ( mobj_t*    thing,
  463.   fixed_t    x,
  464.   fixed_t    y )
  465. {
  466.     fixed_t    oldx;
  467.     fixed_t    oldy;
  468.     int        side;
  469.     int        oldside;
  470.     line_t*    ld;
  471.  
  472.     floatok = false;
  473.     if (!P_CheckPosition (thing, x, y))
  474.     return false;        // solid wall or thing
  475.     
  476.     if ( !(thing->flags & MF_NOCLIP) )
  477.     {
  478.     if (tmceilingz - tmfloorz < thing->height)
  479.         return false;    // doesn't fit
  480.  
  481.     floatok = true;
  482.     
  483.     if ( !(thing->flags&MF_TELEPORT) 
  484.          &&tmceilingz - thing->z < thing->height)
  485.         return false;    // mobj must lower itself to fit
  486.  
  487.     if ( !(thing->flags&MF_TELEPORT)
  488.          && tmfloorz - thing->z > 24*FRACUNIT )
  489.         return false;    // too big a step up
  490.  
  491.     if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT))
  492.          && tmfloorz - tmdropoffz > 24*FRACUNIT )
  493.         return false;    // don't stand over a dropoff
  494.     }
  495.     
  496.     // the move is ok,
  497.     // so link the thing into its new position
  498.     P_UnsetThingPosition (thing);
  499.  
  500.     oldx = thing->x;
  501.     oldy = thing->y;
  502.     thing->floorz = tmfloorz;
  503.     thing->ceilingz = tmceilingz;    
  504.     thing->x = x;
  505.     thing->y = y;
  506.  
  507.     P_SetThingPosition (thing);
  508.     
  509.     // if any special lines were hit, do the effect
  510.     if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
  511.     {
  512.     while (numspechit--)
  513.     {
  514.         // see if the line was crossed
  515.             check_numspechit ("P_CheckPosition");
  516.         ld = spechit[numspechit];
  517.         side = P_PointOnLineSide (thing->x, thing->y, ld);
  518.         oldside = P_PointOnLineSide (oldx, oldy, ld);
  519.         if (side != oldside)
  520.         {
  521.         if (ld->special)
  522.             P_CrossSpecialLine (ld-lines, oldside, thing);
  523.         }
  524.     }
  525.     }
  526.  
  527.     return true;
  528. }
  529.  
  530.  
  531. //
  532. // P_ThingHeightClip
  533. // Takes a valid thing and adjusts the thing->floorz,
  534. // thing->ceilingz, and possibly thing->z.
  535. // This is called for all nearby monsters
  536. // whenever a sector changes height.
  537. // If the thing doesn't fit,
  538. // the z will be set to the lowest value
  539. // and false will be returned.
  540. //
  541. boolean P_ThingHeightClip (mobj_t* thing)
  542. {
  543.     boolean        onfloor;
  544.     
  545.     onfloor = (thing->z == thing->floorz);
  546.     
  547.     P_CheckPosition (thing, thing->x, thing->y);    
  548.     // what about stranding a monster partially off an edge?
  549.     
  550.     thing->floorz = tmfloorz;
  551.     thing->ceilingz = tmceilingz;
  552.     
  553.     if (onfloor)
  554.     {
  555.     // walking monsters rise and fall with the floor
  556.     thing->z = thing->floorz;
  557.     }
  558.     else
  559.     {
  560.     // don't adjust a floating monster unless forced to
  561.     if (thing->z+thing->height > thing->ceilingz)
  562.         thing->z = thing->ceilingz - thing->height;
  563.     }
  564.     
  565.     if (thing->ceilingz - thing->floorz < thing->height)
  566.     return false;
  567.         
  568.     return true;
  569. }
  570.  
  571.  
  572.  
  573. //
  574. // SLIDE MOVE
  575. // Allows the player to slide along any angled walls.
  576. //
  577. fixed_t        bestslidefrac;
  578. fixed_t        secondslidefrac;
  579.  
  580. line_t*        bestslideline;
  581. line_t*        secondslideline;
  582.  
  583. mobj_t*        slidemo;
  584.  
  585. fixed_t        tmxmove;
  586. fixed_t        tmymove;
  587.  
  588.  
  589.  
  590. //
  591. // P_HitSlideLine
  592. // Adjusts the xmove / ymove
  593. // so that the next move will slide along the wall.
  594. //
  595. void P_HitSlideLine (line_t* ld)
  596. {
  597.     int            side;
  598.  
  599.     angle_t        lineangle;
  600.     angle_t        moveangle;
  601.     angle_t        deltaangle;
  602.     
  603.     fixed_t        movelen;
  604.     fixed_t        newlen;
  605.     
  606.     
  607.     if (ld->slopetype == ST_HORIZONTAL)
  608.     {
  609.     tmymove = 0;
  610.     return;
  611.     }
  612.     
  613.     if (ld->slopetype == ST_VERTICAL)
  614.     {
  615.     tmxmove = 0;
  616.     return;
  617.     }
  618.     
  619.     side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
  620.     
  621.     lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
  622.  
  623.     if (side == 1)
  624.     lineangle += ANG180;
  625.  
  626.     moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
  627.     deltaangle = moveangle-lineangle;
  628.  
  629.     if (deltaangle > ANG180)
  630.     deltaangle += ANG180;
  631.     //    I_Error ("SlideLine: ang>ANG180");
  632.  
  633.     lineangle >>= ANGLETOFINESHIFT;
  634.     deltaangle >>= ANGLETOFINESHIFT;
  635.     
  636.     movelen = P_AproxDistance (tmxmove, tmymove);
  637.     newlen = FixedMul (movelen, finecosine[deltaangle]);
  638.  
  639.     tmxmove = FixedMul (newlen, finecosine[lineangle]);    
  640.     tmymove = FixedMul (newlen, finesine[lineangle]);    
  641. }
  642.  
  643.  
  644. //
  645. // PTR_SlideTraverse
  646. //
  647. boolean PTR_SlideTraverse (intercept_t* in)
  648. {
  649.     line_t*    li;
  650.     
  651.     if (!in->isaline)
  652.     I_Error ("PTR_SlideTraverse: not a line?");
  653.         
  654.     li = in->d.line;
  655.     
  656.     if ( ! (li->flags & ML_TWOSIDED) )
  657.     {
  658.     if (P_PointOnLineSide (slidemo->x, slidemo->y, li))
  659.     {
  660.         // don't hit the back side
  661.         return true;        
  662.     }
  663.     goto isblocking;
  664.     }
  665.  
  666.     // set openrange, opentop, openbottom
  667.     P_LineOpening (li);
  668.     
  669.     if (openrange < slidemo->height)
  670.     goto isblocking;        // doesn't fit
  671.         
  672.     if (opentop - slidemo->z < slidemo->height)
  673.     goto isblocking;        // mobj is too high
  674.  
  675.     if (openbottom - slidemo->z > 24*FRACUNIT )
  676.     goto isblocking;        // too big a step up
  677.  
  678.     // this line doesn't block movement
  679.     return true;        
  680.     
  681.     // the line does block movement,
  682.     // see if it is closer than best so far
  683.   isblocking:        
  684.     if (in->frac < bestslidefrac)
  685.     {
  686.     secondslidefrac = bestslidefrac;
  687.     secondslideline = bestslideline;
  688.     bestslidefrac = in->frac;
  689.     bestslideline = li;
  690.     }
  691.     
  692.     return false;    // stop
  693. }
  694.  
  695.  
  696.  
  697. //
  698. // P_SlideMove
  699. // The momx / momy move is bad, so try to slide
  700. // along a wall.
  701. // Find the first line hit, move flush to it,
  702. // and slide along it
  703. //
  704. // This is a kludgy mess.
  705. //
  706. void P_SlideMove (mobj_t* mo)
  707. {
  708.     fixed_t        leadx;
  709.     fixed_t        leady;
  710.     fixed_t        trailx;
  711.     fixed_t        traily;
  712.     fixed_t        newx;
  713.     fixed_t        newy;
  714.     int            hitcount;
  715.         
  716.     slidemo = mo;
  717.     hitcount = 0;
  718.     
  719.   retry:
  720.     if (++hitcount == 3)
  721.     goto stairstep;        // don't loop forever
  722.  
  723.     
  724.     // trace along the three leading corners
  725.     if (mo->momx > 0)
  726.     {
  727.     leadx = mo->x + mo->radius;
  728.     trailx = mo->x - mo->radius;
  729.     }
  730.     else
  731.     {
  732.     leadx = mo->x - mo->radius;
  733.     trailx = mo->x + mo->radius;
  734.     }
  735.     
  736.     if (mo->momy > 0)
  737.     {
  738.     leady = mo->y + mo->radius;
  739.     traily = mo->y - mo->radius;
  740.     }
  741.     else
  742.     {
  743.     leady = mo->y - mo->radius;
  744.     traily = mo->y + mo->radius;
  745.     }
  746.         
  747.     bestslidefrac = FRACUNIT+1;
  748.     
  749.     P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
  750.              PT_ADDLINES, PTR_SlideTraverse );
  751.     P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
  752.              PT_ADDLINES, PTR_SlideTraverse );
  753.     P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
  754.              PT_ADDLINES, PTR_SlideTraverse );
  755.     
  756.     // move up to the wall
  757.     if (bestslidefrac == FRACUNIT+1)
  758.     {
  759.     // the move most have hit the middle, so stairstep
  760.       stairstep:
  761.     if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
  762.         P_TryMove (mo, mo->x + mo->momx, mo->y);
  763.     return;
  764.     }
  765.  
  766.     // fudge a bit to make sure it doesn't hit
  767.     bestslidefrac -= 0x800;    
  768.     if (bestslidefrac > 0)
  769.     {
  770.     newx = FixedMul (mo->momx, bestslidefrac);
  771.     newy = FixedMul (mo->momy, bestslidefrac);
  772.     
  773.     if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
  774.         goto stairstep;
  775.     }
  776.     
  777.     // Now continue along the wall.
  778.     // First calculate remainder.
  779.     bestslidefrac = FRACUNIT-(bestslidefrac+0x800);
  780.     
  781.     if (bestslidefrac > FRACUNIT)
  782.     bestslidefrac = FRACUNIT;
  783.     
  784.     if (bestslidefrac <= 0)
  785.     return;
  786.     
  787.     tmxmove = FixedMul (mo->momx, bestslidefrac);
  788.     tmymove = FixedMul (mo->momy, bestslidefrac);
  789.  
  790.     P_HitSlideLine (bestslideline);    // clip the moves
  791.  
  792.     mo->momx = tmxmove;
  793.     mo->momy = tmymove;
  794.         
  795.     if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove))
  796.     {
  797.     goto retry;
  798.     }
  799. }
  800.  
  801.  
  802. //
  803. // P_LineAttack
  804. //
  805. mobj_t*        linetarget;    // who got hit (or NULL)
  806. mobj_t*        shootthing;
  807.  
  808. // Height if not aiming up or down
  809. // ???: use slope for monsters?
  810. fixed_t        shootz;    
  811.  
  812. int        la_damage;
  813. fixed_t        attackrange;
  814.  
  815. fixed_t        aimslope;
  816.  
  817. // slopes to top and bottom of target
  818. extern fixed_t    topslope;
  819. extern fixed_t    bottomslope;    
  820.  
  821.  
  822. //
  823. // PTR_AimTraverse
  824. // Sets linetaget and aimslope when a target is aimed at.
  825. //
  826. boolean
  827. PTR_AimTraverse (intercept_t* in)
  828. {
  829.     line_t*        li;
  830.     mobj_t*        th;
  831.     fixed_t        slope;
  832.     fixed_t        thingtopslope;
  833.     fixed_t        thingbottomslope;
  834.     fixed_t        dist;
  835.         
  836.     if (in->isaline)
  837.     {
  838.     li = in->d.line;
  839.     
  840.     if ( !(li->flags & ML_TWOSIDED) )
  841.         return false;        // stop
  842.     
  843.     // Crosses a two sided line.
  844.     // A two sided line will restrict
  845.     // the possible target ranges.
  846.     P_LineOpening (li);
  847.     
  848.     if (openbottom >= opentop)
  849.         return false;        // stop
  850.     
  851.     dist = FixedMul (attackrange, in->frac);
  852.  
  853.     if (li->frontsector->floorheight != li->backsector->floorheight)
  854.     {
  855.         slope = FixedDiv (openbottom - shootz , dist);
  856.         if (slope > bottomslope)
  857.         bottomslope = slope;
  858.     }
  859.         
  860.     if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  861.     {
  862.         slope = FixedDiv (opentop - shootz , dist);
  863.         if (slope < topslope)
  864.         topslope = slope;
  865.     }
  866.         
  867.     if (topslope <= bottomslope)
  868.         return false;        // stop
  869.             
  870.     return true;            // shot continues
  871.     }
  872.     
  873.     // shoot a thing
  874.     th = in->d.thing;
  875.     if (th == shootthing)
  876.     return true;            // can't shoot self
  877.     
  878.     if (!(th->flags&MF_SHOOTABLE))
  879.     return true;            // corpse or something
  880.  
  881.     // check angles to see if the thing can be aimed at
  882.     dist = FixedMul (attackrange, in->frac);
  883.     thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  884.  
  885.     if (thingtopslope < bottomslope)
  886.     return true;            // shot over the thing
  887.  
  888.     thingbottomslope = FixedDiv (th->z - shootz, dist);
  889.  
  890.     if (thingbottomslope > topslope)
  891.     return true;            // shot under the thing
  892.     
  893.     // this thing can be hit!
  894.     if (thingtopslope > topslope)
  895.     thingtopslope = topslope;
  896.     
  897.     if (thingbottomslope < bottomslope)
  898.     thingbottomslope = bottomslope;
  899.  
  900.     aimslope = (thingtopslope+thingbottomslope)/2;
  901.     linetarget = th;
  902.  
  903.     return false;            // don't go any farther
  904. }
  905.  
  906.  
  907. //
  908. // PTR_ShootTraverse
  909. //
  910. boolean PTR_ShootTraverse (intercept_t* in)
  911. {
  912.     fixed_t        x;
  913.     fixed_t        y;
  914.     fixed_t        z;
  915.     fixed_t        frac;
  916.     
  917.     line_t*        li;
  918.     
  919.     mobj_t*        th;
  920.  
  921.     fixed_t        slope;
  922.     fixed_t        dist;
  923.     fixed_t        thingtopslope;
  924.     fixed_t        thingbottomslope;
  925.         
  926.     if (in->isaline)
  927.     {
  928.     li = in->d.line;
  929.     
  930.     if (li->special)
  931.         P_ShootSpecialLine (shootthing, li);
  932.  
  933.     if ( !(li->flags & ML_TWOSIDED) )
  934.         goto hitline;
  935.     
  936.     // crosses a two sided line
  937.     P_LineOpening (li);
  938.         
  939.     dist = FixedMul (attackrange, in->frac);
  940.  
  941.     if (li->frontsector->floorheight != li->backsector->floorheight)
  942.     {
  943.         slope = FixedDiv (openbottom - shootz , dist);
  944.         if (slope > aimslope)
  945.         goto hitline;
  946.     }
  947.         
  948.     if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
  949.     {
  950.         slope = FixedDiv (opentop - shootz , dist);
  951.         if (slope < aimslope)
  952.         goto hitline;
  953.     }
  954.  
  955.     // shot continues
  956.     return true;
  957.     
  958.     
  959.     // hit line
  960.       hitline:
  961.     // position a bit closer
  962.     frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
  963.     x = trace.x + FixedMul (trace.dx, frac);
  964.     y = trace.y + FixedMul (trace.dy, frac);
  965.     z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
  966.  
  967.     if (li->frontsector->ceilingpic == skyflatnum)
  968.     {
  969.         // don't shoot the sky!
  970.         if (z > li->frontsector->ceilingheight)
  971.         return false;
  972.         
  973.         // it's a sky hack wall
  974.         if    (li->backsector && li->backsector->ceilingpic == skyflatnum)
  975.         return false;        
  976.     }
  977.  
  978.     // Spawn bullet puffs.
  979.     P_SpawnPuff (x,y,z);
  980.     
  981.     // don't go any farther
  982.     return false;    
  983.     }
  984.     
  985.     // shoot a thing
  986.     th = in->d.thing;
  987.     if (th == shootthing)
  988.     return true;        // can't shoot self
  989.     
  990.     if (!(th->flags&MF_SHOOTABLE))
  991.     return true;        // corpse or something
  992.         
  993.     // check angles to see if the thing can be aimed at
  994.     dist = FixedMul (attackrange, in->frac);
  995.     thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
  996.  
  997.     if (thingtopslope < aimslope)
  998.     return true;        // shot over the thing
  999.  
  1000.     thingbottomslope = FixedDiv (th->z - shootz, dist);
  1001.  
  1002.     if (thingbottomslope > aimslope)
  1003.     return true;        // shot under the thing
  1004.  
  1005.     
  1006.     // hit thing
  1007.     // position a bit closer
  1008.     frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
  1009.  
  1010.     x = trace.x + FixedMul (trace.dx, frac);
  1011.     y = trace.y + FixedMul (trace.dy, frac);
  1012.     z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
  1013.  
  1014.     // Spawn bullet puffs or blod spots,
  1015.     // depending on target type.
  1016.     if (in->d.thing->flags & MF_NOBLOOD)
  1017.     P_SpawnPuff (x,y,z);
  1018.     else
  1019.     P_SpawnBlood (x,y,z, la_damage);
  1020.  
  1021.     if (la_damage)
  1022.     P_DamageMobj (th, shootthing, shootthing, la_damage);
  1023.  
  1024.     // don't go any farther
  1025.     return false;
  1026.     
  1027. }
  1028.  
  1029.  
  1030. //
  1031. // P_AimLineAttack
  1032. //
  1033. fixed_t
  1034. P_AimLineAttack
  1035. ( mobj_t*    t1,
  1036.   angle_t    angle,
  1037.   fixed_t    distance )
  1038. {
  1039.     fixed_t    x2;
  1040.     fixed_t    y2;
  1041.     
  1042.     angle >>= ANGLETOFINESHIFT;
  1043.     shootthing = t1;
  1044.     
  1045.     x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1046.     y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1047.     shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1048.  
  1049.     // can't shoot outside view angles
  1050.     topslope = 100*FRACUNIT/160;    
  1051.     bottomslope = -100*FRACUNIT/160;
  1052.     
  1053.     attackrange = distance;
  1054.     linetarget = NULL;
  1055.     
  1056.     P_PathTraverse ( t1->x, t1->y,
  1057.              x2, y2,
  1058.              PT_ADDLINES|PT_ADDTHINGS,
  1059.              PTR_AimTraverse );
  1060.         
  1061.     if (linetarget)
  1062.     return aimslope;
  1063.  
  1064.     return 0;
  1065. }
  1066.  
  1067.  
  1068. //
  1069. // P_LineAttack
  1070. // If damage == 0, it is just a test trace
  1071. // that will leave linetarget set.
  1072. //
  1073. void
  1074. P_LineAttack
  1075. ( mobj_t*    t1,
  1076.   angle_t    angle,
  1077.   fixed_t    distance,
  1078.   fixed_t    slope,
  1079.   int        damage )
  1080. {
  1081.     fixed_t    x2;
  1082.     fixed_t    y2;
  1083.     
  1084.     angle >>= ANGLETOFINESHIFT;
  1085.     shootthing = t1;
  1086.     la_damage = damage;
  1087.     x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
  1088.     y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
  1089.     shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
  1090.     attackrange = distance;
  1091.     aimslope = slope;
  1092.         
  1093.     P_PathTraverse ( t1->x, t1->y,
  1094.              x2, y2,
  1095.              PT_ADDLINES|PT_ADDTHINGS,
  1096.              PTR_ShootTraverse );
  1097. }
  1098.  
  1099.  
  1100.  
  1101. //
  1102. // USE LINES
  1103. //
  1104. mobj_t*        usething;
  1105.  
  1106. boolean    PTR_UseTraverse (intercept_t* in)
  1107. {
  1108.     int        side;
  1109.     
  1110.     if (!in->d.line->special)
  1111.     {
  1112.     P_LineOpening (in->d.line);
  1113.     if (openrange <= 0)
  1114.     {
  1115.         S_StartSound (usething, sfx_noway);
  1116.         
  1117.         // can't use through a wall
  1118.         return false;    
  1119.     }
  1120.     // not a special line, but keep checking
  1121.     return true ;        
  1122.     }
  1123.     
  1124.     side = 0;
  1125.     if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
  1126.     side = 1;
  1127.     
  1128.     //    return false;        // don't use back side
  1129.     
  1130.     P_UseSpecialLine (usething, in->d.line, side);
  1131.  
  1132.     // can't use for than one special line in a row
  1133.     return false;
  1134. }
  1135.  
  1136.  
  1137. //
  1138. // P_UseLines
  1139. // Looks for special lines in front of the player to activate.
  1140. //
  1141. void P_UseLines (player_t*    player) 
  1142. {
  1143.     int        angle;
  1144.     fixed_t    x1;
  1145.     fixed_t    y1;
  1146.     fixed_t    x2;
  1147.     fixed_t    y2;
  1148.     
  1149.     usething = player->mo;
  1150.         
  1151.     angle = player->mo->angle >> ANGLETOFINESHIFT;
  1152.  
  1153.     x1 = player->mo->x;
  1154.     y1 = player->mo->y;
  1155.     x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
  1156.     y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
  1157.     
  1158.     P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
  1159. }
  1160.  
  1161.  
  1162. //
  1163. // RADIUS ATTACK
  1164. //
  1165. mobj_t*        bombsource;
  1166. mobj_t*        bombspot;
  1167. int        bombdamage;
  1168.  
  1169.  
  1170. //
  1171. // PIT_RadiusAttack
  1172. // "bombsource" is the creature
  1173. // that caused the explosion at "bombspot".
  1174. //
  1175. boolean PIT_RadiusAttack (mobj_t* thing)
  1176. {
  1177.     fixed_t    dx;
  1178.     fixed_t    dy;
  1179.     fixed_t    dist;
  1180.     
  1181.     if (!(thing->flags & MF_SHOOTABLE) )
  1182.     return true;
  1183.  
  1184.     // Boss spider and cyborg
  1185.     // take no damage from concussion.
  1186.     if (thing->type == MT_CYBORG
  1187.     || thing->type == MT_SPIDER)
  1188.     return true;    
  1189.         
  1190.     dx = iabs(thing->x - bombspot->x);
  1191.     dy = iabs(thing->y - bombspot->y);
  1192.     
  1193.     dist = dx>dy ? dx : dy;
  1194.     dist = (dist - thing->radius) >> FRACBITS;
  1195.  
  1196.     if (dist < 0)
  1197.     dist = 0;
  1198.  
  1199.     if (dist >= bombdamage)
  1200.     return true;    // out of range
  1201.  
  1202.     if ( P_CheckSight (thing, bombspot) )
  1203.     {
  1204.     // must be in direct path
  1205.     P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist);
  1206.     }
  1207.     
  1208.     return true;
  1209. }
  1210.  
  1211.  
  1212. //
  1213. // P_RadiusAttack
  1214. // Source is the creature that caused the explosion at spot.
  1215. //
  1216. void
  1217. P_RadiusAttack
  1218. ( mobj_t*    spot,
  1219.   mobj_t*    source,
  1220.   int        damage )
  1221. {
  1222.     int        x;
  1223.     int        y;
  1224.     
  1225.     int        xl;
  1226.     int        xh;
  1227.     int        yl;
  1228.     int        yh;
  1229.     
  1230.     fixed_t    dist;
  1231.     
  1232.     dist = (damage+MAXRADIUS)<<FRACBITS;
  1233.     yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
  1234.     yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
  1235.     xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
  1236.     xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
  1237.     bombspot = spot;
  1238.     bombsource = source;
  1239.     bombdamage = damage;
  1240.     
  1241.     for (y=yl ; y<=yh ; y++)
  1242.     for (x=xl ; x<=xh ; x++)
  1243.         P_BlockThingsIterator (x, y, PIT_RadiusAttack );
  1244. }
  1245.  
  1246.  
  1247.  
  1248. //
  1249. // SECTOR HEIGHT CHANGING
  1250. // After modifying a sectors floor or ceiling height,
  1251. // call this routine to adjust the positions
  1252. // of all things that touch the sector.
  1253. //
  1254. // If anything doesn't fit anymore, true will be returned.
  1255. // If crunch is true, they will take damage
  1256. //  as they are being crushed.
  1257. // If Crunch is false, you should set the sector height back
  1258. //  the way it was and call P_ChangeSector again
  1259. //  to undo the changes.
  1260. //
  1261. boolean        crushchange;
  1262. boolean        nofit;
  1263.  
  1264.  
  1265. //
  1266. // PIT_ChangeSector
  1267. //
  1268. boolean PIT_ChangeSector (mobj_t*    thing)
  1269. {
  1270.     mobj_t*    mo;
  1271.     
  1272.     if (P_ThingHeightClip (thing))
  1273.     {
  1274.     // keep checking
  1275.     return true;
  1276.     }
  1277.     
  1278.  
  1279.     // crunch bodies to giblets
  1280.     if (thing->health <= 0)
  1281.     {
  1282.     P_SetMobjState (thing, S_GIBS);
  1283.  
  1284.     thing->flags &= ~MF_SOLID;
  1285.     thing->height = 0;
  1286.     thing->radius = 0;
  1287.  
  1288.     // keep checking
  1289.     return true;        
  1290.     }
  1291.  
  1292.     // crunch dropped items
  1293.     if (thing->flags & MF_DROPPED)
  1294.     {
  1295.     P_RemoveMobj (thing);
  1296.     
  1297.     // keep checking
  1298.     return true;        
  1299.     }
  1300.  
  1301.     if (! (thing->flags & MF_SHOOTABLE) )
  1302.     {
  1303.     // assume it is bloody gibs or something
  1304.     return true;            
  1305.     }
  1306.     
  1307.     nofit = true;
  1308.  
  1309.     if (crushchange && !(leveltime&3) )
  1310.     {
  1311.     P_DamageMobj(thing,NULL,NULL,10);
  1312.  
  1313.     // spray blood in a random direction
  1314.     mo = P_SpawnMobj (thing->x,
  1315.               thing->y,
  1316.               thing->z + thing->height/2, MT_BLOOD);
  1317.     
  1318.     mo->momx = (P_Random() - P_Random ())<<12;
  1319.     mo->momy = (P_Random() - P_Random ())<<12;
  1320.     }
  1321.  
  1322.     // keep checking (crush other things)    
  1323.     return true;    
  1324. }
  1325.  
  1326.  
  1327.  
  1328. //
  1329. // P_ChangeSector
  1330. //
  1331. boolean
  1332. P_ChangeSector
  1333. ( sector_t*    sector,
  1334.   boolean    crunch )
  1335. {
  1336.     int        x;
  1337.     int        y;
  1338.     
  1339.     nofit = false;
  1340.     crushchange = crunch;
  1341.     
  1342.     // re-check heights for all things near the moving sector
  1343.     for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
  1344.     for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
  1345.         P_BlockThingsIterator (x, y, PIT_ChangeSector);
  1346.     
  1347.     
  1348.     return nofit;
  1349. }
  1350.  
  1351.